using System.Web.UI;
using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Reflection;
using Web.Ajax.Data;

namespace Web.Ajax.Controls
{
    [ToolboxData("<{0}:Object runat=\"server\"></{0}:Object>")]
	[ParseChildren(false)]
    public class Object : AjaxControl
    {
        public Object()
        {
            PassPageParameters = true;
        }

        private int columns=2;
        public int Columns
        {
            get { return columns; }
            set { columns = value; }
        }

        private bool showRefresh=true;
        public bool ShowRefresh
        {
            get { return showRefresh; }
            set { showRefresh = value; }
        }

        private string onEdit;
        public string OnEdit
        {
            get { return onEdit; }
            set { onEdit = value; }
        }

        private bool editInSitu;
        public bool EditInSitu
        {
            get { return editInSitu; }
            set { editInSitu = value; }
        }

        public enum ObjectMode
        {
            View=0,
            Edit=1
        }

        private ObjectMode mode;
        public ObjectMode Mode
        {
            get { return mode; }
            set { mode = value; }
        }

        private List<Property> properties;
        public List<Property> Properties
        {
            get
            {
                if (properties==null)
                {
                    properties = new List<Property>();
                    for (int i = 0; i < Controls.Count; i++)
                    {
                        Control c = Controls[i];
                        if(c is Web.Ajax.Controls.Property)
                            properties.Add((Web.Ajax.Controls.Property)Controls[i]);
                    }
                }
                return properties;
            }
        }

        protected override void OnInit(EventArgs e)
        {
            Ajax.RegisterAjaxMethods(this);
            base.OnInit(e);
            if (Page != null)
            {
				Page.RegisterJavascriptFile(Resources.Javascript.AjaxControl);
				Page.RegisterStyleSheet(Resources.StyleSheets.Object);
                Page.RegisterJavascriptFile(Resources.Javascript.Object);
                Page.RegisterStyleSheet(Resources.StyleSheets.Calendar);
                Page.RegisterJavascriptFile(Resources.Javascript.Calendar);
                Page.RegisterStyleSheet(Resources.StyleSheets.PopupMenu);
                Page.RegisterJavascriptFile(Resources.Javascript.PopupMenu);
                Page.RegisterJavascriptFile(Resources.Javascript.Validator);
            }
        }

        public delegate object GetDataMethod(ObjectInfo oi);
        public GetDataMethod DataMethod;

        public string RenderButtons()
        {
            StringBuilder html = new StringBuilder();
            html.Append("<span class=\"ObjectButtons\">");
            if (ShowRefresh)
                html.Append("&nbsp;<input type=\"button\" value=\"Rrefresh\" class=\"button2\" onclick=\""+JavascriptId+".GetData();\" />");
            string editscript = OnEdit;
            if (EditInSitu)
                editscript = JavascriptId + ".SwitchMode();";
            if (!string.IsNullOrEmpty(editscript))
            {
                string savescript = JavascriptId + ".Save();";
                html.Append("&nbsp;<input id=\"" + JavascriptId + "_EditButton\" type=\"button\" value=\"Edit\" class=\"button\" onclick=\"" + editscript + "\" />");
                html.Append("<span id=\"" + JavascriptId + "_SaveSpan\" style=\"display:none;\">&nbsp;");
                html.Append("<input id=\"" + JavascriptId + "_SaveButton\"  type=\"button\" value=\"Save\" class=\"button\" onclick=\"" + savescript + "\" />");
                html.Append("</span>");
            }
            html.Append("</span>");
            return html.ToString();
        }

        protected override void Render(HtmlTextWriter writer)
        {
            //if (DataMethod == null)
            //    throw new Exception("DataMethod was not set on ObjectControl: " + JavascriptId + ". A DataMethod must be provided for the ObjectControl to work.");
            if (!Visible)
                return;
            StringBuilder html = new StringBuilder();
            html.Append("<div class=\"ObjectPanel\" >");            
            html.Append(RenderButtons());
            html.Append("<div class=\"DataHeading\" id=\"" + JavascriptId + "_Title\"></div>");
            html.Append("<div id=\"" + JavascriptId + "_Content\"></div>");
            html.Append("</div>");
            writer.Write(html.ToString());
            writer.WriteLine("<script type=\"text/javascript\">");
            RenderObjectInit(writer, "ObjectControl", DataMethod);
            RenderParameters(writer);
            RenderProperty(writer, "Properties", Properties.ToArray());
            RenderProperty(writer, "Columns", Columns);
            RenderProperty(writer, "Mode", Mode);
            RenderJavascriptId(writer);
            if (!DelayLoading)
                writer.WriteLine(JavascriptId + ".GetData();");
            writer.WriteLine("</script>");
        }

        [Ajax]
        public static ObjectResponse GetData(ObjectRequest request)
        {
            ObjectResponse response = new ObjectResponse();
            try
            {
                Type Type = System.Type.GetType(request.DataMethodType);
                if (Type == null)
                    throw new Exception("ObjectControl: Invalid Type.");
                MethodInfo Method = Type.GetMethod(request.DataMethodName);
                if (request.ObjectInfo.Parameters == null)
                    request.ObjectInfo.Parameters = new Parameter[0];
                object o = null;
                o = Method.Invoke(null, new object[] { request.ObjectInfo });
              
                response.Properties = request.ObjectInfo.Properties;
                response.OnComplete = request.ObjectInfo.OnComplete;
                response.Title = request.ObjectInfo.Title;
                response.Bind(o);
            }
            catch (Exception e)
            {
                Logging.Log.Error(e);
                if (e.InnerException != null)
                    response.Message = e.InnerException.Message;
                else
                    response.Message = e.Message;
            }
            return response;
        }
    }

    [ToolboxData("<{0}:Property runat=\"server\" Title=\"?\" Binding=\"?\" />")]
    [ParseChildren(false)]
    [Json(IgnoreParent = true)]
    public class Property : WebControl
    {
        private string title;
        public string Title
        {
            get { return title; }
            set { title = value; }
        }

        private string binding;
        public string Binding
        {
            get { return binding; }
            set { binding = value; }
        }

        private object ValueField;
        public object Value
        {
            get { return ValueField; }
            set { ValueField = value; }
        }

        private string valueHtml;
        public string ValueHtml
        {
            get { return valueHtml; }
            set { valueHtml = value; }
        }

        private int colSpan=1;
        /// <summary>
        /// Each Property is one Column. (i.e. one column translates to two table cells.)
        /// </summary>
        public int ColSpan
        {
            get { return colSpan; }
            set { colSpan = value; }
        }

        private int rowSpan = 1;
        public int RowSpan
        {
            get { return rowSpan; }
            set { rowSpan = value; }
        }

        private bool readOnly;
        public bool ReadOnly
        {
            get { return readOnly; }
            set { readOnly = value; }
        }

        private string type;
        public string Type
        {
            get{return type;}
            set{type=value;}
        }

        private string textBoxWidth;
        public string TextBoxWidth
        {
            get { return textBoxWidth; }
            set { textBoxWidth = value; }
        }

        private string onRender;
        public string OnRender
        {
            get { return onRender; }
            set { onRender = value; }
        }

        private bool required;
        public bool Required
        {
            get { return required; }
            set { required = value; }
        }

        private string regEx;
        public string RegEx
        {
            get { return regEx; }
            set { regEx = value; }
        }

        private Option[] options;
        public Option[] Options
        {
            get { return options; }
            set { options = value; }
        }

        private bool visible=true;
        public bool Visible
        {
            get { return visible; }
            set { visible = value; }
        }

        private void SetValue(object o)
        {
            Value = o;            
            return;/*
            Type t = o.GetType();
            if (t.IsArray)
            {
                r = "";
               
                IList a=(IList)o;               
                for (int i = 0; i < a.Count; i++)
                {
                    if (i > 0)
                        r += ", ";
                    r+=Convert( a[i]);
                }
                Value = r;
                return;
            }
            Value=o.ToString();*/
        }        

        private void SetHtmlType(Type t)
        {
            if (t == null)
            {
                this.Type="text";
                return;
            }
            if (t == typeof(bool) || t == typeof(bool?))
            {
                this.Type="checkbox";
                return;
            }
            if (t == typeof(DateTime) || t == typeof(DateTime?))
            {
                this.Type = "Calendar";
                return;
            }
            System.Type EnumType=null;                
            Type InnerType = Nullable.GetUnderlyingType(t);
            if (t.IsEnum)
                EnumType = t;
            if (EnumType==null&&(InnerType != null && InnerType.IsEnum))
                EnumType=InnerType;
            if (EnumType != null)
            {
                this.Type= "select";                
                List<Option> list = new List<Option>();
                Options = Option.Populate(EnumType);
                return;
            }
            this.Type="text";
        }
               
        public void Bind(object o)
        {
            if (o == null||string.IsNullOrEmpty(Binding))
                return;
            Type t = o.GetType();
            object val=null;
            Type valType = null;
            bool InvalidBinding = true;
            PropertyInfo pi=t.GetProperty(Binding);
            if (pi != null)
            {
                val = pi.GetValue(o, null);
                valType = pi.PropertyType;
                InvalidBinding = false;
            }
            if (val == null)
            {
                FieldInfo fi=t.GetField(Binding);
                if (fi != null)
                {
                    val = fi.GetValue(o);
                    valType = fi.FieldType;
                    InvalidBinding = false;
                }
            }
            if (InvalidBinding)
            {
                Value = "<span style=\"color:red\">Invalid Binding: " + Binding + "</span>";
                return;
            }            
            SetValue(val);
            SetHtmlType(valType);
        }

        public class Option
        {
            public string Text;
            public string Value;

            public static Option[] Populate(Type t)
            {
                List<Option> list = new List<Option>();
                IList vals = Enum.GetValues(t);
                for (int i = 0; i < vals.Count; i++)
                {
                    Option o = new Option();
                    o.Value = vals[i].ToString();
                    o.Text = Enum.GetName(t, vals[i]);
                    list.Add(o);
                }
                return list.ToArray();
            }
        }
    }

    public class ObjectInfo : ControlInfo
    {
        public string Title;
        public Property[] Properties;
    }

    public class ObjectRequest : AjaxControlRequest
    {
        public ObjectInfo ObjectInfo;
    }

    public class ObjectResponse : AjaxControlResponse
    {
        public string Title;
        public Property[] Properties;

        public void Bind(object o)
        {
            if (Properties == null)
                return;
            for (int i = 0; i < Properties.Length; i++)
                Properties[i].Bind(o);
        }
    }
}
